<!--
    调用说明：
    1、比如先通过一个按钮的点击事件，调用该组件的Init方法
    2、通过回调的submit事件，来获取返回的图片路径
    3、特别说明，该组件的显示/隐藏是不用在父组件中去处理的，因为该组件内部已经处理了
-->
<template>
    <MyDialog title="签名" v-model="thisData.isShow" :type="DialogType.C2" top="3%" append-to-body @close="onClose">
        <!-- 编辑状态 -->
        <div class="signatureBox" v-if="isEdit">
            <div class="canvasBox" ref="CanvasBoxRef">
                <canvas ref="CanvasRef" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp"></canvas>
            </div>
        </div>

        <!-- 查看状态 -->
        <div v-if="!isEdit">
            <img :src="thisData.imgSrc" alt="" class="w-100" />
        </div>

        <template #footer v-if="isEdit">
            <el-button type="primary" plain @click="onSbumit">确定</el-button>
        </template>
    </MyDialog>
</template>

<script lang="ts" setup>
import { TipsType, DialogType } from "@/_gx/TsEnums";

//定义接收参数
const props = defineProps({
    isEdit: {
        type: Boolean,
        default: true,
    },

    fileName: {
        type: String,
        default: "签名.png",
    },
});

//定义变量
const thisData = reactive({
    isShow: false,
    points: [],
    canvasTxt: null,
    startX: 0,
    startY: 0,
    moveY: 0,
    moveX: 0,
    endY: 0,
    endX: 0,
    w: null,
    h: null,
    isDown: false,
    color: "#000",
    linewidth: 3,
    isDraw: false,
    imgSrc: "",
});

//定义Ref
const CanvasBoxRef = ref(null);
const CanvasRef = ref(null);

//初始化
const Init = (src: string | null | undefined) => {
    thisData.isShow = true;

    if (!props.isEdit && src) {
        //非编辑且src有值，则只做显示
        nextTick(() => {
            thisData.imgSrc = src;
        });
    } else {
        nextTick(() => {
            let canvas = CanvasRef.value;
            canvas.height = CanvasBoxRef.value.clientHeight - 10;
            canvas.width = CanvasBoxRef.value.clientWidth;

            thisData.canvasTxt = CanvasRef.value.getContext("2d");
            thisData.canvasTxt.strokeStyle = thisData.color;
            thisData.canvasTxt.lineWidth = thisData.linewidth;
        });
    }
};

//关闭
const onClose = () => {
    if (props.isEdit) {
        thisData.canvasTxt.clearRect(0, 0, CanvasRef.value.width, CanvasRef.value.height);
        thisData.points = [];
        thisData.isDraw = false;
    }
    thisData.isShow = false;
};

//确定
const onSbumit = () => {
    //对于空的验证，如果这里不验证，则下面就会上传一个空的签名图片并返回
    let blank = document.createElement("canvas");
    blank.width = CanvasRef.value.width;
    blank.height = CanvasRef.value.height;
    if (blank.toDataURL() === CanvasRef.value.toDataURL()) {
        App.Tips({ msg: "请在空白处签名！" });
        return;
    }

    let imgBase64 = CanvasRef.value.toDataURL();
    let arr = imgBase64.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }

    let file = new File([u8arr], props.fileName, { type: mime });

    App.Upload(file)
        .then((res) => {
            App.Tips({ msg: "签名成功！", type: TipsType.Success });
            emits("submit", res.url);
            thisData.isShow = false;
        })
        .catch((err) => {
            console.log(err);
        });
};

//PC端鼠标移动
const onMouseMove = (ev) => {
    ev = ev || event;
    ev.preventDefault();
    if (thisData.isDown) {
        let obj = {
            x: ev.offsetX,
            y: ev.offsetY,
        };
        thisData.moveY = obj.y;
        thisData.moveX = obj.x;
        thisData.canvasTxt.moveTo(thisData.startX, thisData.startY);
        thisData.canvasTxt.lineTo(obj.x, obj.y);
        thisData.canvasTxt.stroke();
        thisData.startY = obj.y;
        thisData.startX = obj.x;
        thisData.points.push(obj);
    }
};

//PC端鼠标按下
const onMouseDown = (ev) => {
    ev = ev || event;
    ev.preventDefault();
    let obj = {
        x: ev.offsetX,
        y: ev.offsetY,
    };

    thisData.startX = obj.x;
    thisData.startY = obj.y;
    thisData.canvasTxt.beginPath();
    thisData.points.push(obj);
    thisData.isDown = true;
};

//PC端鼠标松开
const onMouseUp = (ev) => {
    ev = ev || event;
    ev.preventDefault();
    if (1) {
        let obj = {
            x: ev.offsetX,
            y: ev.offsetY,
        };
        thisData.canvasTxt.closePath();
        thisData.points.push(obj);
        thisData.points.push({ x: -1, y: -1 });
        thisData.isDown = false;
    }
};

//移动端手按下
const onTouchStart = (ev) => {
    ev = ev || event;
    ev.preventDefault();
    if (ev.touches.length == 1) {
        thisData.isDraw = true; //签名标记
        let obj = {
            x: ev.targetTouches[0].clientX - 180,
            y: ev.targetTouches[0].clientY - (document.body.offsetHeight * 0.1 + CanvasBoxRef.value.offsetHeight * 0.1),
        };
        thisData.startX = obj.x;
        thisData.startY = obj.y;
        thisData.canvasTxt.beginPath();
        thisData.points.push(obj);
    }
};

//移动端手移动
const onTouchMove = (ev) => {
    ev = ev || event;
    ev.preventDefault();
    if (ev.touches.length == 1) {
        let obj = {
            x: ev.targetTouches[0].clientX - 180,
            y: ev.targetTouches[0].clientY - (document.body.offsetHeight * 0.1 + CanvasBoxRef.value.offsetHeight * 0.1),
        };
        thisData.moveY = obj.y;
        thisData.moveX = obj.x;
        thisData.canvasTxt.moveTo(thisData.startX, thisData.startY);
        thisData.canvasTxt.lineTo(obj.x, obj.y);
        thisData.canvasTxt.stroke();
        thisData.startY = obj.y;
        thisData.startX = obj.x;
        thisData.points.push(obj);
    }
};

//移动端手松开
const onTouchEnd = (ev) => {
    ev = ev || event;
    ev.preventDefault();
    if (ev.touches.length == 1) {
        let obj = {
            x: ev.targetTouches[0].clientX - 180,
            y: ev.targetTouches[0].clientY - (document.body.offsetHeight * 0.1 + CanvasBoxRef.value.offsetHeight * 0.1),
        };
        thisData.canvasTxt.closePath();
        thisData.points.push(obj);
        thisData.points.push({ x: -1, y: -1 });
    }
};

const emits = defineEmits(["submit"]);
defineExpose({ Init });
</script>

<style lang="scss" scoped>
@import "@/assets/css/variables.scss";

.signatureBox {
    width: 100%;
    box-sizing: border-box;
    padding-bottom: 5px;
}

.canvasBox {
    height: 50vh;
}

canvas {
    border: 1px solid $global-border-color;
}

@media only screen and (min-width: 730px) {
    .signatureBox {
        width: 100%;
        box-sizing: border-box;
    }
}
</style>
